package tasks;

import jade.core.AID;
import jade.core.Agent;

import jade.domain.FIPANames;

import jade.lang.acl.ACLMessage;

import java.io.IOException;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Random;
import java.util.Vector;

public class ManagerAgent extends Agent {
    int numOfTasks;
    
    ArrayList<Long> task;
    long[] spec;
    int[] contractors;
    
    public static final int MAX_NUM_COMP = 4;
    
    private Random rand = new Random();
    
    public ManagerAgent() {
        super();
    }
    
    protected void setup() {
        Object[] arguments = getArguments();
        if(arguments.length < 1) {
            System.err.println("Specify at least one contractor");
            return;
        }
        //generate the tasks
        //numOfTasks = 1 + rand.nextInt(MAX_NUM_COMP);
        numOfTasks = MAX_NUM_COMP;
        task = ConfigurationManager.generateTask(numOfTasks);
        spec = new long[numOfTasks];
        contractors = new int[numOfTasks];
        Arrays.fill(spec, (3 * ConfigurationManager.MAX_PRICE) <<
                    (3 * ConfigurationManager.B_SIZE));
        Arrays.fill(contractors, -1);
        //add the contract net behaviour
        setupContractNet(arguments);
    }

    private void setupContractNet(Object[] arguments) {
        ACLMessage msg = new ACLMessage(ACLMessage.CFP);
        msg.setProtocol(FIPANames.InteractionProtocol.FIPA_CONTRACT_NET);
        for(Object arg: arguments) {
            msg.addReceiver(new AID(arg.toString(), AID.ISLOCALNAME));
        }
        try {
            msg.setContentObject(task);
            msg.setReplyByDate(new Date(System.currentTimeMillis() + 10000));
            addBehaviour(new ContractNetIB(this, msg));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    void evaluateProposals(ArrayList<ArrayList<Long>> content, int agentIndex) {
        int idx = 0;
        for(ArrayList<Long> proposalList : content) {
            for(Long proposal : proposalList) {
                evaluateProposal(proposal, idx, agentIndex);
            }
            idx++;
        }
    }

    private void evaluateProposal(long proposal, int taskIndex, int agentIndex) 
    {
        if((proposal >> (3 * ConfigurationManager.B_SIZE)) <
           (spec[taskIndex] >> (3 * ConfigurationManager.B_SIZE))) {
            spec[taskIndex] = proposal;
            contractors[taskIndex] = agentIndex;
        }
    }

    void createAcceptances(Vector acceptances) {
        for(int taskIdx = 0;taskIdx < numOfTasks;taskIdx++) {
            if(contractors[taskIdx] != -1) {
                ACLMessage msg = (ACLMessage)acceptances.get(
                    contractors[taskIdx]);
                msg.setContent(msg.getContent() + spec[taskIdx] + 
                           ConfigurationManager.SEPARATOR);
                msg.setPerformative(ACLMessage.ACCEPT_PROPOSAL);
            } else {
                System.out.println("Unable to find supplier for " + 
                    ConfigurationManager.configurationToString(
                    task.get(taskIdx)));
            }
        }
    }
}
